﻿namespace BlogsAPI.Search
{
    using Abstract;
    using System.IO;
    using System.Net;
    using System.Text;
    using System.Text.RegularExpressions;
    using RssToolkit.Rss;
    using System.Diagnostics;
    using System;
    using System.Web;

    /// <summary>
    /// Класс для работы с поиском по блогам на базе WORDPRESS
    /// </summary>
    public class Wordpress : BasicSearch
    {
        /// <summary>
        /// максимальное число подгружаемых в поиске страниц
        /// </summary>
        private const int MAXPAGES = 50;

        /// <summary>
        /// Необходимо убивать этот тэг, по причине невозможности распарсить его внутреннее значение
        /// </summary>
        /// <remarks>http://code.google.com/p/doctype/wiki/EthCharacterEntity</remarks>
        private readonly Regex _opensearch = new Regex(@"<opensearch:Query[^>]+>\s*(?:</opensearch:Query>)?",
            RegexOptions.Singleline | RegexOptions.Compiled);

        /// <summary>
        /// Конструктор
        /// </summary>
        public Wordpress()
        {
            separator_and = " AND ";
            separator_or = " OR ";
            separator_not = "!";
        }

        /// <summary>
        /// Формируем ссылку для поиска в яндексе числа отзывов и комментов
        /// </summary>
        /// <param name="text">текст для поиска</param>
        /// <param name="page">номер страницы</param>
        /// <returns>Ссылка для поиска в рускоязычном wordpress'e</returns>
        private static String FormSearch(String text, int page = 1)
        {
            return String.Format("http://ru.search.wordpress.com/?q={0}&page={1}&s=date&f=feed",
                HttpUtility.UrlEncode(text).Replace("&", "%26"), page);
        }

        /// <summary>
        /// Формирование разобранного поста из того что дает яндекс.
        /// </summary>
        /// <param name="yad"></param>
        /// <returns></returns>
        private BlogPost ParseBlogPost(RssItem yad)
        {
            return new BlogPost
            {
                Link = new Uri(yad.Link),
                Body = yad.Description,
                Subject = yad.Title,
                Existance = true,
                Published = yad.PubDateParsed
            };
        }

        /// <summary>
        /// </summary>
        /// <param name="text">текст для поиска</param>
        /// <param name="fromDate">дата начиная с которой искать объекты, может быть нулом, тогде по максимуму!</param>
        /// <returns>массив постов удовлетворяющих поиску</returns>
        public override BlogPost[] SearchFor(String text, DateTime? fromDate)
        {
            BlogPost[] oRes = new BlogPost[0];
            try
            {
                for (int p = 1; p <= MAXPAGES; p++)
                {
                    HttpWebRequest myHttpWebRequest = MakeRequest(FormSearch(text, p));
                    myHttpWebRequest.AllowAutoRedirect = false;
                    myHttpWebRequest.Method = "GET";
                    HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
                    string reply = (new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding.UTF8)).ReadToEnd();
                    myHttpWebResponse.Close();
                    //Убираем ошибку неправильных символов
                    reply = _opensearch.Replace(reply, "");
                    //а теперь разбираем
                    RssDocument rss = RssDocument.Load(reply);
                    if (rss != null)//разобрали, и начинаем считать
                    {
                        for (int i = 0; i < rss.Channel.Items.Count; i++)
                        {
                            //если пост слишком старый, то заканчиваем работу.
                            if ((fromDate != null && rss.Channel.Items[i].PubDateParsed < fromDate)
                                || rss.Channel.YaCount < oRes.Length)//слишком 
                            {
                                p = MAXPAGES;
                                break;
                            }
                            BlogPost bp = ParseBlogPost(rss.Channel.Items[i]);
                            if (bp != null)
                            {
                                Array.Resize(ref oRes, oRes.Length + 1);
                                oRes[oRes.Length - 1] = bp;
                            }
                        }
                        //если слишком мало данных, то нет смысла проходить все страницы дальше
                        if (rss.Channel.Items.Count < 10)
                        {
                            break;
                        }
                    }
                }
            }
            catch (Exception e1)
            {
                Debug.WriteLine("SearchFor failed cause " + e1.Message);
            }
            return oRes;
        }

        public override BlogPost[] SearchFor(Uri link, DateTime? fromDate)
        {
            if(link.OriginalString.Contains("?"))//есть параметры, то поиск не возможен
            {
                return new BlogPost[0];
            }
            return base.SearchFor(link, fromDate);
        }
    }
}
